var _ = require('lodash'),
    Q = require('q'),
    BaseEnum = require('../../../Base/server/controllers/Enum'),
    ProduceWorkEnum = require('../../../ProduceWork/server/controllers/Enum.server.controller.js'),
    BaseFun = require('../../../Base/server/controllers/Function'),
    QCEnum = require('../../../QC/server/controllers/Enum.server.controller'),
    Transaction = require('../../../Base/server/controllers/Transaction'),
    BarcodeEnum = require('../../../Barcode/server/controllers/Enum.server.controller'),
    barcodeMasterController = require('../../../Barcode/server/controllers/BarcodeMaster.server.controller'),
    operationController = require('../../../CBO/server/controllers/Operation.server.controller'),
    qcRecordController = require('../../../QC/server/controllers/QCRecord.server.controller'),
    extendEnumController = require('../../../Common/server/controllers/ExtendEnum.server.controller'),
    wareHouseController = require('../../../CBO/server/controllers/WareHouse.server.controller'),
    badTypeBindController = require('../../../QC/server/controllers/BadTypeBind.server.controller');

exports.getSpecialMaster = function(req, res) {
    var barcode = req.body.Barcode;

    queryMaster(barcode, QCEnum.QCStatus.Special.Value).then(function(result) {
        res.json({
            Data: result,
            Error: null
        });
    }, function(err) {
        res.json({
            Data: null,
            Error: err
        });
    });
};

exports.getDecideMaster = function(req, res) {
    var barcode = req.body.Barcode;

    queryMaster(barcode, QCEnum.QCStatus.Decide.Value).then(function(result) {
        res.json({
            Data: result,
            Error: null
        });
    }, function(err) {
        res.json({
            Data: null,
            Error: err
        });
    });
};

exports.getQCRecords = function(req, res) {
    var bizRecord = req.body.BizRecord;

    queryQCRecords(bizRecord).then(function(result) {
        res.json({
            Data: result,
            Error: null
        });
    }, function(err) {
        res.json({
            Data: null,
            Error: err
        });
    });
};

exports.doJudge = function(req, res) {
    var parameter = req.body,
        barcodes = parameter.Barcode,
        terminal = parameter.Terminal,
        terminalName = parameter.TerminalName,
        department = parameter.Department,
        workId = parameter.Work,
        userId = parameter.UserID,
        QCStatus = parameter.QCStatus,
        Remark = parameter.Remark || '';

    if (_.isString(barcodes)) {
        barcodes = [barcodes];
    }

    var dateNow = Date.now(),
        bizRecord = {
            Terminal: terminal,
            TerminalName: terminalName,
            CollectDateTime: dateNow,
            BusinessStatus: 1,
            Users: [userId],
            QCUser: userId,
            QCDateTime: dateNow,
            QCStatus: QCStatus,
            Remark: Remark
        },
        transactions = [],
        barcodeMasterRecords,
        curOperation;

    barcodeMasterController.findBarcodeMasters(barcodes).then(function(records) {
        barcodeMasterRecords = records;
        return queryOperation(records[0], workId);
    }).then(function(operation) {
        curOperation = operation;
        if (QCStatus === QCEnum.QCStatus.Concession.Value && operation && operation.IsStoragePoint) {
            return addStockQty(barcodeMasterRecords, userId, department);
        } else {
            return Q.resolve();
        }
    }).then(function(tran) {
        if (tran) {
            transactions.push(tran);
        }
        return updateBizData(barcodeMasterRecords, bizRecord, curOperation);
    }).then(function(trans) {
        transactions = transactions.concat(trans);
        return Q.nfcall(Transaction.BatchSaveByTran, transactions);
    }).then(function() {
        res.json({
            Data: true,
            Error: null
        });
    }).catch(function(err) {
        res.json({
            Data: null,
            Error: err
        });
    })
    .done();
};

exports.getExtendEnum = function(req, res) {
    var parameter = req.body.Parameter,
        code = parameter.Code;

    queryExtendEnumOption(code).then(function(result) {
        res.json({
            Data: result,
            Error: null
        });
    }, function(err) {
        res.json({
            Data: null,
            Error: err
        });
    });
};

exports.isSystemEnum = function(req, res) {
    var parameter = req.body.Parameter,
        code = parameter.Code,
        value = parameter.Value;

    queryExtendEnumOption(code).then(function(result) {
        var obj = {};
        _.forEach(result, function(v,key) {
            obj[v] = v;
        });

        if (obj.hasOwnProperty(value)) {
            res.json({
                Data: {
                    flg: true
                },
                Error: null
            });
        } else {
            res.json({
                Data: {
                    flg: false
                },
                Error: null
            });
        }
    }, function(err) {
        res.json({
            Data: null,
            Error: err
        });
    });
};

function queryMaster(barcode, requiredQCEnum) {
    var deferred = Q.defer();

    queryBarcodeMaster(barcode).then(function(barcodeMasterRecord) {
        if (barcodeMasterRecord.BarcodeType === BarcodeEnum.BarcodeType.ItemMaster.Value) {
            return queryMasterInfo(barcodeMasterRecord, requiredQCEnum);
        } else {
            var newErr = new Error();
            newErr.leval = 9;
            newErr.title = '无法识别条码';
            newErr.message = '无法识别的条码，请重新扫描！';
            return Q.reject(newErr);
        }
    }).then(function(result) {
        deferred.resolve(result);
    }, function(err) {
        deferred.reject(err);
    });

    return deferred.promise;
}

function queryBarcodeMaster(barcode) {
    var deferred = Q.defer();

    barcodeMasterController.findBarcodeMaster(barcode, function(err, barcodeMasterRecord) {
        if (err) {
            deferred.reject(err);
            return;
        }
        if (barcodeMasterRecord == null) {
            var newErr = new Error();
            newErr.leval = 9;
            newErr.title = '无法识别条码';
            newErr.message = '无法识别的条码，请重新扫描！';
            deferred.reject(newErr);
            return;
        }
        deferred.resolve(barcodeMasterRecord);
    });

    return deferred.promise;
}

function queryMasterInfo(barcodeMaster, requiredQCEnum) {
    var deferred = Q.defer();

    if (barcodeMaster.QCStatus !== requiredQCEnum) {
        var newErr = new Error();
        newErr.leval = 9;
        newErr.message = '物品' + barcodeMaster.ItemMasterCode;
        if (barcodeMaster.QCStatus) {
            newErr.message += '，当前质检状态为';
            if (barcodeMaster.QCStatus == QCEnum.QCStatus.Qualified.Value) {
                newErr.message += '合格';
            } else if (barcodeMaster.QCStatus == QCEnum.QCStatus.Concession.Value) {
                newErr.message += '让步接收';
            } else if (barcodeMaster.QCStatus == QCEnum.QCStatus.Decide.Value) {
                newErr.message += '品质判定';
            } else if (barcodeMaster.QCStatus == QCEnum.QCStatus.Rework.Value) {
                newErr.message += '返工';
            } else if (barcodeMaster.QCStatus == QCEnum.QCStatus.Scrap.Value) {
                newErr.message += '报废';
            } else if (barcodeMaster.QCStatus == QCEnum.QCStatus.Special.Value) {
                newErr.message += '特裁';
            }
        } else {
            newErr.message += '，当前还没有进行过质检';
        }
        newErr.message += '，无需';
        if (requiredQCEnum === QCEnum.QCStatus.Special.Value) {
            newErr.message += '特裁';
        } else if (requiredQCEnum === QCEnum.QCStatus.Decide.Value) {
            newErr.message += '品质判定';
        }

        deferred.reject(newErr);
    } else {
        var result = {
            Barcode: barcodeMaster.Barcode,
            MOCode: barcodeMaster.MOCode,
            WorkName: barcodeMaster.WorkName,
            WorkLocationName: barcodeMaster.WorkLocationName,
            MOLotNumber: barcodeMaster.MOLotNumber,
            ItemMasterCode: barcodeMaster.ItemMasterCode,
            ItemMasterName: barcodeMaster.ItemMasterName,
            Users: barcodeMaster.Users
        };
        if (barcodeMaster.ItemMaster) {
            result.Specification = barcodeMaster.ItemMaster.Specification;
        }
        if (barcodeMaster.BizRecord) {
            result.BizRecord = barcodeMaster.BizRecord._id;
            result.Remark = barcodeMaster.BizRecord.Remark;
        }
        deferred.resolve(result);
    }
    return deferred.promise;
}

function queryQCRecords(bizRecordId) {
    var deferred = Q.defer();

    qcRecordController.findQCRecordByBizRecordID(bizRecordId, function(err, qcRecords) {
        if (err) {
            deferred.reject(err);
            return;
        }
        var enumOptions = {};
        Q.all([
            queryBadExtendEnum('BadType', enumOptions),
            queryBadExtendEnum('BadPosition', enumOptions)
        ]).then(function() {
            var badQCRecords = [],
                batches = [];
            _.forEach(qcRecords, function(qcRecord) {
                batches.push(collectQCRecords(qcRecord, enumOptions, badQCRecords));
            });
            Q.all(batches).finally(function() {
                deferred.resolve(badQCRecords);
            });
        }, function(err) {
            deferred.reject(err);
        });
    });

    return deferred.promise;
}

function collectQCRecords(qcRecord, enumOptions, results) {
    var deferred = Q.defer();

    if (qcRecord.BadType !== undefined) {
        results.push({
            BadType: enumOptions.BadType[qcRecord.BadType],
            BadPosition: enumOptions.BadPosition[qcRecord.BadPosition],
            Description: qcRecord.Description,
            Images: qcRecord.Images
        });
        deferred.resolve();
    } else if (qcRecord.NormValue !== undefined) {
        badTypeBindController.findBadTypeByQCNormID(qcRecord.QCNorm._id, function(err, records) {
            if (err || !records || (records.length === 0)) {
                deferred.resolve();
                return;
            }
            var temp = {
                BadType: enumOptions.BadType[records[0].BadType],
                NormValue: qcRecord.NormValue,
                Description: qcRecord.Description,
                Images: qcRecord.Images
            };
            if (qcRecord.QCStandard) {
                temp.StandardValue = qcRecord.QCStandard.StandardValue;
                temp.DiffValue = qcRecord.NormValue - qcRecord.QCStandard.StandardValue;
            }
            results.push(temp);
            deferred.resolve();
        });
    }

    return deferred.promise;
}

function queryBadExtendEnum(enumCode, target) {
    var deferred = Q.defer();

    queryExtendEnumOption(enumCode).then(function(option) {
        target[enumCode] = option;
        deferred.resolve();
    }, function(err) {
        deferred.reject(err);
    });

    return deferred.promise;
}

function queryExtendEnumOption(enumCode) {
    var deferred = Q.defer();

    extendEnumController.findEnumOptions(enumCode, function(err, option) {
        if (err) {
            deferred.reject(err);
        } else {
            deferred.resolve(option);
        }
    });
    return deferred.promise;
}

function updateBizData(barcodeMasterRecords, bizRecord, curOperation) {
    var deferred = Q.defer();

    var bizRecords = [],
        barcodeMasters = [];
    _.forEach(barcodeMasterRecords, function(barcodeMasterRecord) {
        var tempbizRecord = {
            _id: BaseFun.getObjectId(),
            RowStatus: BaseEnum.RowStatus.Insert.Value,
            CreatedBy: bizRecord.QCUser,
            BarcodeMaster: barcodeMasterRecord._id,
            WorkLocation: barcodeMasterRecord.WorkLocation,
            WorkLocationName: barcodeMasterRecord.WorkLocationName,
            QCType: barcodeMasterRecord.QCType
        };
        if (barcodeMasterRecord.Work) {
            tempbizRecord.Work = barcodeMasterRecord.Work._id;
            tempbizRecord.WorkName = barcodeMasterRecord.Work.Name;
        }
        if (barcodeMasterRecord.Operation) {
            tempbizRecord.Operation = barcodeMasterRecord.Operation._id;
            tempbizRecord.OperationName = barcodeMasterRecord.Operation.Name;
        }
        _.merge(tempbizRecord, bizRecord);
        bizRecords.push(tempbizRecord);

        var uRecord = {
            RowStatus: BaseEnum.RowStatus.Modify.Value,
            ModifyBy: bizRecord.QCUser,
            SysVersion: barcodeMasterRecord.SysVersion,
            _id: barcodeMasterRecord._id,
            BizRecord: tempbizRecord._id,
            Terminal: bizRecord.Terminal,
            TerminalName: bizRecord.TerminalName,
            Users: bizRecord.Users,
            BusinessStatus: bizRecord.BusinessStatus,
            QCStatus: bizRecord.QCStatus
        };

        if (bizRecord.QCStatus === QCEnum.QCStatus.Qualified.Value ||
            bizRecord.QCStatus === QCEnum.QCStatus.Concession.Value
        ) {
            if (curOperation && barcodeMasterRecord.QCReworkOperation) {
                if (barcodeMasterRecord.QCReworkOperation._id.toString() === curOperation._id.toString()) {
                    uRecord.QCReworkOperation = null;
                }
            }
        } else if (bizRecord.QCStatus === QCEnum.QCStatus.Rework.Value) {
            _.merge(uRecord, {
                ReworkQty: barcodeMasterRecord.reworkQty ? (barcodeMasterRecord.reworkQty + 1) : 1,
                QCReworkOperation: barcodeMasterRecord.Operation
            });
            if (barcodeMasterRecord.Operation) {
                tempbizRecord.QCReworkOperation = barcodeMasterRecord.Operation._id;
            }
        }
        barcodeMasters.push(uRecord);
    });

    deferred.resolve([{
        EntityName: 'BizRecord',
        Records: bizRecords
    }, {
        EntityName: 'BarcodeMaster',
        Records: barcodeMasters
    }]);

    return deferred.promise;
}

function addStockQty(barcodeMasters, userId, department) {
    var deferred = Q.defer();

    wareHouseController.findByDepartmentDeep(department).then(function(wareHouse) {
        if (!wareHouse) {
            var newErr = new Error();
            newErr.leval = 9;
            newErr.title = '查询仓库';
            newErr.message = '没有找到对应的仓库';
            deferred.reject(newErr);
            return;
        }
        var stockQties = [];
        _.forEach(barcodeMasters, function(barcodeMaster) {
            if (barcodeMaster.Operation && barcodeMaster.Operation.IsStoragePoint) {
                stockQties.push({
                    RowStatus: BaseEnum.RowStatus.Insert.Value,
                    CreatedBy: userId,
                    RcvBusinessType: ProduceWorkEnum.RcvBusinessType.WareHouse.Value,
                    RcvQty: 1,
                    BarcodeMaster: barcodeMaster._id,
                    Barcode: barcodeMaster.Barcode,
                    ItemMaster: barcodeMaster.ItemMaster ? barcodeMaster.ItemMaster._id : null,
                    DescSeg1: barcodeMaster.DescSeg1,
                    DescSeg2: barcodeMaster.DescSeg2,
                    BusinessDocID: barcodeMaster.MO ? barcodeMaster.MO._id : null,
                    RcvUser: userId,
                    RcvOperation: barcodeMaster.Operation ? barcodeMaster.Operation._id : null,
                    BizRecord: barcodeMaster.BizRecord ? barcodeMaster.BizRecord._id : null,
                    WareHouse: wareHouse._id
                });
            }
        });
        if (stockQties.length === 0) {
            deferred.resolve();
        } else {
            deferred.resolve({
                EntityName: 'RcvRecord',
                Records: stockQties
            });
        }
    }, function(err) {
        deferred.reject(err);
    });

    return deferred.promise;
}

function queryOperation(barcodeMaster, work) {
    var deferred = Q.defer();

    if (!barcodeMaster.ItemMaster) {
        var newErr = new Error();
        newErr.leval = 9;
        newErr.message = '主档未绑定物料';
        deferred.reject(newErr);
        return;
    }
    operationController.findByItemMasterAndWork(barcodeMaster.ItemMaster._id, work, function(err, result) {
        if (err) {
            deferred.reject(err);
            return;
        }
        if (!result) {
            var newErr = new Error();
            newErr.leval = 9;
            newErr.title = '非法数据';
            newErr.message = '没有找到对应的工序';
            deferred.reject(newErr);
            return;
        }
        deferred.resolve(result);
    });

    return deferred.promise;
}
